package com.atguigu.gmall.list.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.list.dao.Goodsdao;
import com.atguigu.gmall.list.service.ListService;
import com.atguigu.gmall.model.list.Goods;
import com.atguigu.gmall.model.list.SearchAttr;
import com.atguigu.gmall.model.list.SearchParam;
import com.atguigu.gmall.model.list.SearchResponseVo;
import com.atguigu.gmall.model.product.BaseCategoryView;
import com.atguigu.gmall.model.product.BaseTrademark;
import com.atguigu.gmall.model.product.SkuAttrValue;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeginClient;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 检索管理 索引库
 * 添加
 * 删除
 * 查询
 * 修改等操作
 */
@Service
public class ListServiceImpl implements ListService {
    @Autowired
    private Goodsdao goodsdao;
    @Autowired
    private ProductFeginClient productFeginClient;
    @Autowired
    private RedisTemplate redisTemplate;
    //删除索引
    @Override
    public void lowerGoods(Long skuId) {
        goodsdao.deleteById(skuId);
    }
    //添加索引
    @Override
    public void upperGoods(Long skuId) {
        Goods goods = new Goods();

        //1:SkuInfo   ID、标题（商品名称）价格 图片
        SkuInfo skuInfo = productFeginClient.getSkuInfo(skuId);
        goods.setId(skuInfo.getId());
        goods.setTitle(skuInfo.getSkuName());
        goods.setPrice(skuInfo.getPrice().doubleValue());
        goods.setDefaultImg(skuInfo.getSkuDefaultImg());
        //2:品牌
        //ID
        BaseTrademark baseTrademark = productFeginClient.getBaseTrademark(skuInfo.getTmId());
        goods.setTmId(baseTrademark.getId());
        //名称
        goods.setTmName(baseTrademark.getTmName());
        //Logo图片
        goods.setTmLogoUrl(baseTrademark.getLogoUrl());
        //3:一二三级分类  ID /名称
        BaseCategoryView categoryView = productFeginClient.getCategoryView(skuInfo.getCategory3Id());
        goods.setCategory1Id(categoryView.getCategory1Id());
        goods.setCategory2Id(categoryView.getCategory2Id());
        goods.setCategory3Id(categoryView.getCategory3Id());
        goods.setCategory1Name(categoryView.getCategory1Name());
        goods.setCategory2Name(categoryView.getCategory2Name());
        goods.setCategory3Name(categoryView.getCategory3Name());
        //4:平台属性集合  Lomda
        List<SkuAttrValue> attrList = productFeginClient.getAttrList(skuId);

        List<SearchAttr> searchAttrList = attrList.stream().map(skuAttrValue -> {
            SearchAttr searchAttr = new SearchAttr();
            //平台属性ID
            searchAttr.setAttrId(skuAttrValue.getBaseAttrInfo().getId());
            //平台属性名称
            searchAttr.setAttrName(skuAttrValue.getBaseAttrInfo().getAttrName());
            //平台属性值名称
            searchAttr.setAttrValue(skuAttrValue.getBaseAttrValue().getValueName());
            return searchAttr;
        }).collect(Collectors.toList());
        goods.setAttrs(searchAttrList);
        //5:时间
        goods.setCreateTime(new Date());
        //保存索引
        goodsdao.save(goods);

    }
    //更新索引的热度
    @Override
    public void incrHotScore(Long skuId) {
        //0.先使用缓存进行缓冲操作 每加1分 不要直接操作索引库
        //先将分在缓存追加 追加到一定程度 再更新索引库
        //1-9分 11-19分。。。保存在缓存中
        //Redis 五大数据类型： String类型（值类型） Hash类型（散列类型）
        //List类型（列表类型） Set类型（集合类型） Zset类型（有序集合类型）
        //现在就要是使用zset类型
        //小明 考试的成绩出来： 语文：99分 英语：88分 数学：90分 让你把小明的分数记录下来
        //redisTemplate.opsForZSet().add("小明","语文",99);
        //HotScore热度: skuId 15 88分
        String hotScore = "hotScore";
        //10.0
        Double score = redisTemplate.opsForZSet().incrementScore(hotScore, skuId, 1);//参数3：追加的分数
        System.out.println("当前分数："+score);
        //本次为了测试 10分更新一次索引库 10 20 30 40
        if (score%10 == 0){
            System.out.println("满10分了吗？"+score);
            //1.根据skuid查询goods数据
            Optional<Goods> optional = goodsdao.findById(skuId);
            Goods goods = optional.get();
            //2.更新操作（追加分）
            goods.setHotScore(Math.round(score));
            //3.更新索引库
            goodsdao.save(goods);
            //如果保存的goods中的id已经存在 更新 如果不存在就是添加
            //更新底层是：先删除 再添加
        }


    }
//    @Autowired
//    private ElasticsearchRestTemplate elasticsearchRestTemplate;//Spring Date ES框架
    @Autowired
    private RestHighLevelClient restHighLevelClient;//es 原生Api客户端
    //开始搜索
    @Override
    public SearchResponseVo list(SearchParam searchParam) {
        //1: 构建 SearchRequest 条件对象
        SearchRequest searchRequest = buildSearchRequest(searchParam);
        try {
            //2: 执行搜索
            SearchResponse searchResponse = restHighLevelClient
                    .search(searchRequest, RequestOptions.DEFAULT);
            //3: 解析结果
            SearchResponseVo searchResponseVo = parseSearchResponse(searchResponse);
            return searchResponseVo;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    //解析搜索结果  4部分数据
    private SearchResponseVo parseSearchResponse(SearchResponse searchResponse) {
        SearchResponseVo vo = new SearchResponseVo();
        SearchHits hits = searchResponse.getHits();
        //1:总条数
        long totalHits = hits.getTotalHits();
        System.out.println("总条数：" + totalHits);
        vo.setTotal(totalHits);
        //2:商品集合
        SearchHit[] hits1 = hits.getHits();
        List<Goods> goodsList = Arrays.stream(hits1).map(h -> {
            String sourceAsString = h.getSourceAsString();
            System.out.println(sourceAsString);
            Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
            return goods;
        }).collect(Collectors.toList());
        vo.setGoodsList(goodsList);
        return vo;
    }

    //构建条件对象    入参：6部分数据
    private SearchRequest buildSearchRequest(SearchParam searchParam) {
        //构建条件资源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //1:关键词  （分词） 搜索字段 商品名称   必须有值不能为NULL
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());//查询所有 没有条件
        //2:一二三级分类的ID
        //3:品牌
        //4:平台属性
        //5:排序
        //6:分页（当前页、每页数） //当不设置分页时  默认是1页 默认显示10条数据
        //搜索请求对象
        SearchRequest searchRequest = new SearchRequest();
        //设置索引库的名称
        searchRequest.indices("goods");
        //设置索引库的类型 （可有可无）不影响搜索  （7.0版本以上取消了 type)
        searchRequest.types("info");
        //设置构建条件资源对象
        searchRequest.source(searchSourceBuilder);
        return searchRequest;
    }
}
